package ru.picman.ui;

import ru.picman.Block;
import ru.picman.Egg;
import ru.picman.Entity;
import ru.picman.R;
import ru.picman.World;
import ru.picman.util.ImageLibrary;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;

/**
 * Painter for the entire game world. Paints Blocks, Eggs and Entities.
 * @author David
 *
 */
public class WorldPainter
             implements Paintable
{
	/**
	 * Constructor for the WorldPainter
	 * @param world - The World this WorldPainter should paint.
	 */
	public WorldPainter(World world) {
		this.world = world;
	}
	
	/**
	 * Retrieve current size of tiles.
	 * @return
	 */
	public int getTileSize() {
		return tileSize;
	}
	
	/**
	 * Updates the x- and y-offset for all the tiles this WorldPainter should paint.
	 */
	public void updateTiles() {
		tileSize = (int)Math.min((double)width / world.getWidth(),
		                         (double)height / world.getHeight());
		
		xOffset = ((width - (tileSize * world.getWidth())) >> 1);
		yOffset = ((height - (tileSize * world.getHeight())) >> 1);
		
		if (tileSize == 0)
			return;
		resizeAll();
	}
	
	/**
	 * Updates the world's width and height according to the game's View.
	 */
	private void updateSize() {
		PicmanView view = world.getGame().getView();
		this.width = view.getWidth();
		this.height = view.getHeight();
	}
	
	/**
	 * Resizes all images in the ImageLibrary.
	 */
	private void resizeAll() {
		for (Integer i : ImageLibrary.getAll())
			ImageLibrary.resize(i.intValue(),tileSize,tileSize);
	}
	
	/**
	 * Draws a border around the entire level.
	 * @param canvas - the canvas to paint to.
	 * @param paint - the paint to paint with.
	 */
	private void drawBorder(Canvas canvas, Paint paint) {
		paint.setStyle(Style.FILL);
		paint.setColor(Color.BLACK);
		
		int cw = canvas.getWidth(), ch = canvas.getHeight(), ww = world.getWidth() * world.getTileSize(), wh = world.getHeight() * world.getTileSize();
		
		canvas.drawRect(-xOffset,-yOffset,cw,0,paint); // top
		canvas.drawRect(-xOffset,0,0,wh,paint); // left
		canvas.drawRect(-xOffset,wh,cw,ch,paint); // down
		canvas.drawRect(ww,0,cw,wh,paint); // right
	}
	
	/**
	 * Draws all the eggs the world contains. 
	 * @param canvas - the canvas to paint to.
	 * @param paint - the paint to paint with.
	 */
	private void drawEggs(Canvas canvas, Paint paint) {
		Egg[][] eggs = world.getEggs();
		for (int x = 0; x < world.getWidth(); ++x) {
			for (int y = 0; y < world.getHeight(); ++y) {
				Egg egg = eggs[x][y];
				if (egg != null && egg.isVisible()) {
					if (egg.getPainter() != null)
						egg.getPainter().paint(canvas,paint);
					else
						canvas.drawBitmap(ImageLibrary.getBitmap(egg.getImageID()),x * tileSize,y * tileSize,paint);
				}
			}
		}
	}
	
	/**
	 * Draws the tiles that comprise the gameworld. Steps through the list of tiles, and for each tile
	 * retrieves the corresponding bitmap.This bitmap is then drawn to the canvas.
	 * @param canvas - the canvas to paint to.
	 * @param paint - the paint to paint with.
	 */
	private void drawTiles(Canvas canvas, Paint paint) {
		Block[][] tileGrid = world.getGrid();
		for (int x = 0; x < world.getWidth(); ++x)
			for (int y = 0; y < world.getHeight(); ++y)
				if (tileGrid[x][y] != null)
					canvas.drawBitmap(ImageLibrary.getBitmap(tileGrid[x][y].getImageID()),x * tileSize,y * tileSize,paint);
	}
	
	/**
	 * Draws all entities to the world's canvas. For each entity, it's painter is retrieved and that painter's 
	 * paint-method is called, using the input canvas and paint as parameters.
	 * @param canvas - the canvas to paint to.
	 * @param paint - the paint to paint with.
	 */
	private void drawEntities(Canvas canvas, Paint paint) {
		for (Entity e : world.getEntities())
			e.getPainter().paint(canvas,paint);
	}
	
	/**
	 * Paints the entire world. Draws Egg, entities, the border and the tiles.
	 * @param canvas - the canvas to paint to.
	 * @param paint - the paint to paint with.
	 */
	public void paint(Canvas canvas, Paint paint) {
		if (width != world.getGame().getView().getWidth() || height != world.getGame().getView().getHeight()) {
			updateSize();
			updateTiles();
		}
		canvas.translate(xOffset,yOffset);
		drawEggs(canvas,paint);
		drawEntities(canvas,paint);
		drawBorder(canvas,paint);
		drawTiles(canvas,paint);
	}
	
	//
	
	private int                tileSize;
	private int                xOffset;
	private int                yOffset;
	private int                width, height;
	
	private final World        world;
	
	private static final int[] tileImages = {
	                                            R.drawable.block_stone,
	                                            R.drawable.block_wood,
	                                            R.drawable.block_wood2,
	                                            R.drawable.whiteegg,
	                                            R.drawable.goldenegg
	                                        };
	
	static {
		int size = 32;
		for (int i : tileImages)
			ImageLibrary.load(i,size,size);
	}
}
